/*
 * DIM-SUM操作系统 - CPU ESR寄存器相关定义
 *
 * Copyright (C) 2023 国科础石(重庆)软件有限公司
 *
 * 作者: Dong Peng <w-pengdong@kernelsoft.com>
 *
 * License terms: GNU General Public License (GPL) version 3
 *
 */

#ifndef __CPU_ASM_ESR_H
#define __CPU_ASM_ESR_H

#include <asm/memory.h>
#include <asm/sysreg.h>

#define ESR_ELx_EC_UNKNOWN	(0x00)
#define ESR_ELx_EC_WFx		(0x01)
/* Unallocated EC: 0x02 */
#define ESR_ELx_EC_CP15_32	(0x03)
#define ESR_ELx_EC_CP15_64	(0x04)
#define ESR_ELx_EC_CP14_MR	(0x05)
#define ESR_ELx_EC_CP14_LS	(0x06)
#define ESR_ELx_EC_FP_ASIMD	(0x07)
#define ESR_ELx_EC_CP10_ID	(0x08)
/* Unallocated EC: 0x09 - 0x0B */
#define ESR_ELx_EC_CP14_64	(0x0C)
/* Unallocated EC: 0x0d */
#define ESR_ELx_EC_ILL		(0x0E)
/* Unallocated EC: 0x0F - 0x10 */
#define ESR_ELx_EC_SVC32	(0x11)
#define ESR_ELx_EC_HVC32	(0x12)
#define ESR_ELx_EC_SMC32	(0x13)
/* Unallocated EC: 0x14 */
#define ESR_ELx_EC_SVC64	(0x15)
#define ESR_ELx_EC_HVC64	(0x16)
#define ESR_ELx_EC_SMC64	(0x17)
#define ESR_ELx_EC_SYS64	(0x18)
#define ESR_ELx_EC_SVE		(0x19)
/* Unallocated EC: 0x1A - 0x1E */
#define ESR_ELx_EC_IMP_DEF	(0x1f)
#define ESR_ELx_EC_IABT_LOW	(0x20)
#define ESR_ELx_EC_IABT_CUR	(0x21)
#define ESR_ELx_EC_PC_ALIGN	(0x22)
/* Unallocated EC: 0x23 */
#define ESR_ELx_EC_DABT_LOW	(0x24)
#define ESR_ELx_EC_DABT_CUR	(0x25)
#define ESR_ELx_EC_SP_ALIGN	(0x26)
/* Unallocated EC: 0x27 */
#define ESR_ELx_EC_FP_EXC32	(0x28)
/* Unallocated EC: 0x29 - 0x2B */
#define ESR_ELx_EC_FP_EXC64	(0x2C)
/* Unallocated EC: 0x2D - 0x2E */
#define ESR_ELx_EC_SERROR	(0x2F)
#define ESR_ELx_EC_BREAKPT_LOW	(0x30)
#define ESR_ELx_EC_BREAKPT_CUR	(0x31)
#define ESR_ELx_EC_SOFTSTP_LOW	(0x32)
#define ESR_ELx_EC_SOFTSTP_CUR	(0x33)
#define ESR_ELx_EC_WATCHPT_LOW	(0x34)
#define ESR_ELx_EC_WATCHPT_CUR	(0x35)
/* Unallocated EC: 0x36 - 0x37 */
#define ESR_ELx_EC_BKPT32	(0x38)
/* Unallocated EC: 0x39 */
#define ESR_ELx_EC_VECTOR32	(0x3A)
/* Unallocted EC: 0x3B */
#define ESR_ELx_EC_BRK64	(0x3C)
/* Unallocated EC: 0x3D - 0x3F */
#define ESR_ELx_EC_MAX		(0x3F)

#define ESR_ELx_EC_SHIFT	(26)
#define ESR_ELx_EC_MASK		(UL(0x3F) << ESR_ELx_EC_SHIFT)
#define ESR_ELx_EC(esr)		(((esr) & ESR_ELx_EC_MASK) >> ESR_ELx_EC_SHIFT)

#define ESR_ELx_IL_SHIFT	(25)
#define ESR_ELx_IL		(UL(1) << ESR_ELx_IL_SHIFT)
#define ESR_ELx_ISS_MASK	(ESR_ELx_IL - 1)

/* ISS field definitions shared by different classes */
#define ESR_ELx_WNR_SHIFT	(6)
#define ESR_ELx_WNR		(UL(1) << ESR_ELx_WNR_SHIFT)

/* Shared ISS field definitions for Data/Instruction aborts */
#define ESR_ELx_SET_SHIFT	(11)
#define ESR_ELx_SET_MASK	(UL(3) << ESR_ELx_SET_SHIFT)
#define ESR_ELx_FnV_SHIFT	(10)
#define ESR_ELx_FnV		(UL(1) << ESR_ELx_FnV_SHIFT)
#define ESR_ELx_EA_SHIFT	(9)
#define ESR_ELx_EA		(UL(1) << ESR_ELx_EA_SHIFT)
#define ESR_ELx_S1PTW_SHIFT	(7)
#define ESR_ELx_S1PTW		(UL(1) << ESR_ELx_S1PTW_SHIFT)

/* Shared ISS fault status code(IFSC/DFSC) for Data/Instruction aborts */
#define ESR_ELx_FSC		(0x3F)
#define ESR_ELx_FSC_TYPE	(0x3C)
#define ESR_ELx_FSC_EXTABT	(0x10)
#define ESR_ELx_FSC_ACCESS	(0x08)
#define ESR_ELx_FSC_FAULT	(0x04)
#define ESR_ELx_FSC_PERM	(0x0C)

/* ISS field definitions for Data Aborts */
#define ESR_ELx_ISV_SHIFT	(24)
#define ESR_ELx_ISV		(UL(1) << ESR_ELx_ISV_SHIFT)
#define ESR_ELx_SAS_SHIFT	(22)
#define ESR_ELx_SAS		(UL(3) << ESR_ELx_SAS_SHIFT)
#define ESR_ELx_SSE_SHIFT	(21)
#define ESR_ELx_SSE		(UL(1) << ESR_ELx_SSE_SHIFT)
#define ESR_ELx_SRT_SHIFT	(16)
#define ESR_ELx_SRT_MASK	(UL(0x1F) << ESR_ELx_SRT_SHIFT)
#define ESR_ELx_SF_SHIFT	(15)
#define ESR_ELx_SF 		(UL(1) << ESR_ELx_SF_SHIFT)
#define ESR_ELx_AR_SHIFT	(14)
#define ESR_ELx_AR 		(UL(1) << ESR_ELx_AR_SHIFT)
#define ESR_ELx_CM_SHIFT	(8)
#define ESR_ELx_CM 		(UL(1) << ESR_ELx_CM_SHIFT)

/* ISS field definitions for exceptions taken in to Hyp */
#define ESR_ELx_CV		(UL(1) << 24)
#define ESR_ELx_COND_SHIFT	(20)
#define ESR_ELx_COND_MASK	(UL(0xF) << ESR_ELx_COND_SHIFT)
#define ESR_ELx_WFx_ISS_WFE	(UL(1) << 0)
#define ESR_ELx_xVC_IMM_MASK	((1UL << 16) - 1)

/* ESR value templates for specific events */

/* BRK instruction trap from AArch64 state */
#define ESR_ELx_VAL_BRK64(imm)					\
	((ESR_ELx_EC_BRK64 << ESR_ELx_EC_SHIFT) | ESR_ELx_IL |	\
	 ((imm) & 0xffff))

/* ISS field definitions for System instruction traps */
#define ESR_ELx_SYS64_ISS_RES0_SHIFT	22
#define ESR_ELx_SYS64_ISS_RES0_MASK	(UL(0x7) << ESR_ELx_SYS64_ISS_RES0_SHIFT)
#define ESR_ELx_SYS64_ISS_DIR_MASK	0x1
#define ESR_ELx_SYS64_ISS_DIR_READ	0x1
#define ESR_ELx_SYS64_ISS_DIR_WRITE	0x0

#define ESR_ELx_SYS64_ISS_RT_SHIFT	5
#define ESR_ELx_SYS64_ISS_RT_MASK	(UL(0x1f) << ESR_ELx_SYS64_ISS_RT_SHIFT)
#define ESR_ELx_SYS64_ISS_CRM_SHIFT	1
#define ESR_ELx_SYS64_ISS_CRM_MASK	(UL(0xf) << ESR_ELx_SYS64_ISS_CRM_SHIFT)
#define ESR_ELx_SYS64_ISS_CRN_SHIFT	10
#define ESR_ELx_SYS64_ISS_CRN_MASK	(UL(0xf) << ESR_ELx_SYS64_ISS_CRN_SHIFT)
#define ESR_ELx_SYS64_ISS_OP1_SHIFT	14
#define ESR_ELx_SYS64_ISS_OP1_MASK	(UL(0x7) << ESR_ELx_SYS64_ISS_OP1_SHIFT)
#define ESR_ELx_SYS64_ISS_OP2_SHIFT	17
#define ESR_ELx_SYS64_ISS_OP2_MASK	(UL(0x7) << ESR_ELx_SYS64_ISS_OP2_SHIFT)
#define ESR_ELx_SYS64_ISS_OP0_SHIFT	20
#define ESR_ELx_SYS64_ISS_OP0_MASK	(UL(0x3) << ESR_ELx_SYS64_ISS_OP0_SHIFT)
#define ESR_ELx_SYS64_ISS_SYS_MASK	(ESR_ELx_SYS64_ISS_OP0_MASK | \
					 ESR_ELx_SYS64_ISS_OP1_MASK | \
					 ESR_ELx_SYS64_ISS_OP2_MASK | \
					 ESR_ELx_SYS64_ISS_CRN_MASK | \
					 ESR_ELx_SYS64_ISS_CRM_MASK)
#define ESR_ELx_SYS64_ISS_SYS_VAL(op0, op1, op2, crn, crm) \
					(((op0) << ESR_ELx_SYS64_ISS_OP0_SHIFT) | \
					 ((op1) << ESR_ELx_SYS64_ISS_OP1_SHIFT) | \
					 ((op2) << ESR_ELx_SYS64_ISS_OP2_SHIFT) | \
					 ((crn) << ESR_ELx_SYS64_ISS_CRN_SHIFT) | \
					 ((crm) << ESR_ELx_SYS64_ISS_CRM_SHIFT))

#define ESR_ELx_SYS64_ISS_SYS_OP_MASK	(ESR_ELx_SYS64_ISS_SYS_MASK | \
					 ESR_ELx_SYS64_ISS_DIR_MASK)
/*
 * User space cache operations have the following sysreg encoding
 * in System instructions.
 * op0=1, op1=3, op2=1, crn=7, crm={ 5, 10, 11, 12, 14 }, WRITE (L=0)
 */
#define ESR_ELx_SYS64_ISS_CRM_DC_CIVAC	14
#define ESR_ELx_SYS64_ISS_CRM_DC_CVAP	12
#define ESR_ELx_SYS64_ISS_CRM_DC_CVAU	11
#define ESR_ELx_SYS64_ISS_CRM_DC_CVAC	10
#define ESR_ELx_SYS64_ISS_CRM_IC_IVAU	5

#define ESR_ELx_SYS64_ISS_EL0_CACHE_OP_MASK	(ESR_ELx_SYS64_ISS_OP0_MASK | \
						 ESR_ELx_SYS64_ISS_OP1_MASK | \
						 ESR_ELx_SYS64_ISS_OP2_MASK | \
						 ESR_ELx_SYS64_ISS_CRN_MASK | \
						 ESR_ELx_SYS64_ISS_DIR_MASK)
#define ESR_ELx_SYS64_ISS_EL0_CACHE_OP_VAL \
				(ESR_ELx_SYS64_ISS_SYS_VAL(1, 3, 1, 7, 0) | \
				 ESR_ELx_SYS64_ISS_DIR_WRITE)

#define ESR_ELx_SYS64_ISS_SYS_CTR	ESR_ELx_SYS64_ISS_SYS_VAL(3, 3, 1, 0, 0)
#define ESR_ELx_SYS64_ISS_SYS_CTR_READ	(ESR_ELx_SYS64_ISS_SYS_CTR | \
					 ESR_ELx_SYS64_ISS_DIR_READ)

#define ESR_ELx_SYS64_ISS_SYS_CNTVCT	(ESR_ELx_SYS64_ISS_SYS_VAL(3, 3, 2, 14, 0) | \
					 ESR_ELx_SYS64_ISS_DIR_READ)

#define ESR_ELx_SYS64_ISS_SYS_CNTFRQ	(ESR_ELx_SYS64_ISS_SYS_VAL(3, 3, 0, 14, 0) | \
					 ESR_ELx_SYS64_ISS_DIR_READ)

#define esr_sys64_to_sysreg(e)					\
	sys_reg((((e) & ESR_ELx_SYS64_ISS_OP0_MASK) >>		\
		 ESR_ELx_SYS64_ISS_OP0_SHIFT),			\
		(((e) & ESR_ELx_SYS64_ISS_OP1_MASK) >>		\
		 ESR_ELx_SYS64_ISS_OP1_SHIFT),			\
		(((e) & ESR_ELx_SYS64_ISS_CRN_MASK) >>		\
		 ESR_ELx_SYS64_ISS_CRN_SHIFT),			\
		(((e) & ESR_ELx_SYS64_ISS_CRM_MASK) >>		\
		 ESR_ELx_SYS64_ISS_CRM_SHIFT),			\
		(((e) & ESR_ELx_SYS64_ISS_OP2_MASK) >>		\
		 ESR_ELx_SYS64_ISS_OP2_SHIFT))

#define esr_cp15_to_sysreg(e)					\
	sys_reg(3,						\
		(((e) & ESR_ELx_SYS64_ISS_OP1_MASK) >>		\
		 ESR_ELx_SYS64_ISS_OP1_SHIFT),			\
		(((e) & ESR_ELx_SYS64_ISS_CRN_MASK) >>		\
		 ESR_ELx_SYS64_ISS_CRN_SHIFT),			\
		(((e) & ESR_ELx_SYS64_ISS_CRM_MASK) >>		\
		 ESR_ELx_SYS64_ISS_CRM_SHIFT),			\
		(((e) & ESR_ELx_SYS64_ISS_OP2_MASK) >>		\
		 ESR_ELx_SYS64_ISS_OP2_SHIFT))

// INST
// 0b000000 Address size fault, level 0 of translation or translation table base register.
// 0b000001 Address size fault, level 1.
// 0b000010 Address size fault, level 2.
// 0b000011 Address size fault, level 3.
// DATA
// 0b000000 Address size fault, level 0 of translation or translation table base register.
// 0b000001 Address size fault, level 1.
// 0b000010 Address size fault, level 2.
// 0b000011 Address size fault, level 3.
#define IDFSC_ADDR_SZ_FAULT_L0 (0)
#define IDFSC_ADDR_SZ_FAULT_L1 (1)
#define IDFSC_ADDR_SZ_FAULT_L2 (2)
#define IDFSC_ADDR_SZ_FAULT_L3 (3)
// INST
// 0b000100 Translation fault, level 0.
// 0b000101 Translation fault, level 1.
// 0b000110 Translation fault, level 2.
// 0b000111 Translation fault, level 3.
// DATA
// 0b000100 Translation fault, level 0.
// 0b000101 Translation fault, level 1.
// 0b000110 Translation fault, level 2.
// 0b000111 Translation fault, level 3.
#define IDFSC_TRANS_FAULT_L0 (4)
#define IDFSC_TRANS_FAULT_L1 (5)
#define IDFSC_TRANS_FAULT_L2 (6)
#define IDFSC_TRANS_FAULT_L3 (7)
// INST
// 0b001001 Access flag fault, level 1.
// 0b001010 Access flag fault, level 2.
// 0b001011 Access flag fault, level 3.
// DATA
// 0b001001 Access flag fault, level 1.
// 0b001010 Access flag fault, level 2.
// 0b001011 Access flag fault, level 3.
#define IDFSC_ACCE_FLG_FAULT_L1 (9)
#define IDFSC_ACCE_FLG_FAULT_L2 (10)
#define IDFSC_ACCE_FLG_FAULT_L3 (11)

// INST
// 0b001101 Permission fault, level 1.
// 0b001110 Permission fault, level 2.
// 0b001111 Permission fault, level 3.
// DATA
// 0b001101 Permission fault, level 1.
// 0b001110 Permission fault, level 2.
// 0b001111 Permission fault, level 3.
#define IDFSC_PERMI_FAULT_L1 (13)
#define IDFSC_PERMI_FAULT_L2 (14)
#define IDFSC_PERMI_FAULT_L3 (15)

// INST
// 0b010000 Synchronous External abort, not on translation table walk or hardware update of translation table.
// 0b010100 Synchronous External abort on translation table walk or hardware update of translation table, level 0.
// 0b010101 Synchronous External abort on translation table walk or hardware update of translation table, level 1.
// 0b010110 Synchronous External abort on translation table walk or hardware update of translation table, level 2.
// 0b010111 Synchronous External abort on translation table walk or hardware update of translation table, level 3
// DATA
// 0b010000 Synchronous External abort, not on translation table walk or hardware update of translation table.
// 0b010001 When FEAT_MTE is implemented Synchronous Tag Check Fault.
// 0b010100 Synchronous External abort on translation table walk or hardware update of translation table, level 0
// 0b010101 Synchronous External abort on translation table walk or hardware update of translation table, level 1.
// 0b010110 Synchronous External abort on translation table walk or hardware update of translation table, level 2.
// 0b010111 Synchronous External abort on translation table walk or hardware update of translation table, level 3.

#define IDFSC_SYNC_EXT_WALK_TTBL_NO (16)
#define IDFSC_SYNC_TAG_CHECK_FAULT (17)
#define IDFSC_SYNC_EXT_WALK_TTBL_L0 (20)
#define IDFSC_SYNC_EXT_WALK_TTBL_L1 (21)
#define IDFSC_SYNC_EXT_WALK_TTBL_L2 (22)
#define IDFSC_SYNC_EXT_WALK_TTBL_L3 (23)
// INST
// 0b011000 When FEAT_RAS is not implemented Synchronous parity or ECC error on memory access, not on translation table walk.
// 0b011100 When FEAT_RAS is not implemented Synchronous parity or ECC error on memory access on translation table walk or hardware update of translation table, level 0.
// 0b011101 When FEAT_RAS is not implemented Synchronous parity or ECC error on memory access on translation table walk or hardware update of translation table, level 1.
// 0b011110 When FEAT_RAS is not implemented Synchronous parity or ECC error on memory access on translation table walk or hardware update of translation table, level 2.
// 0b011111 When FEAT_RAS is not implemented Synchronous parity or ECC error on memory access on translation table walk or hardware update of translation table, level 3.
// DATA
// 0b011000 When FEAT_RAS is not implemented Synchronous parity or ECC error on memory access, not on translation table walk.
// 0b011100 When FEAT_RAS is not implemented Synchronous parity or ECC error on memory access on translation table walk or hardware update of translation table, level 0.
// 0b011101 When FEAT_RAS is not implemented Synchronous parity or ECC error on memory access on translation table walk or hardware update of translation table, level 1.
// 0b011110 When FEAT_RAS is not implemented Synchronous parity or ECC error on memory access on translation table walk or hardware update of translation table, level 2.
// 0b011111 When FEAT_RAS is not implemented Synchronous parity or ECC error on memory access on translation table walk or hardware update of translation table, level 3.

#define IDFSC_NFEAT_ECC_WALK_TTBL_NO (24)
#define IDFSC_NFEAT_ECC_WALK_TTBL_L0 (28)
#define IDFSC_NFEAT_ECC_WALK_TTBL_L1 (29)
#define IDFSC_NFEAT_ECC_WALK_TTBL_L2 (30)
#define IDFSC_NFEAT_ECC_WALK_TTBL_L3 (31)

// INST
// 0b110000 TLB conflict abort.
// 0b110001 When FEAT_HAFDBS is implemented Unsupported atomic hardware update fault.
// DATA
// 0b100001 Alignment fault.
// 0b110100 IMPLEMENTATION DEFINED fault (Lockdown).
// 0b110101 IMPLEMENTATION DEFINED fault (Unsupported Exclusive or Atomic access
#define IDFSC_AILGN_FAULT (33)
#define IDFSC_TBL_CONFLICT_ABORT (48)
#define IDFSC_NOT_HW_ATOMIC_UP_FAULT (49)
#define IDFSC_LOCKDOWN_IMP_DEFINED_FAULT (52)
#define IDFSC_NOT_ATOMIC_ACCESS_IMP_DEFINED_FAULT (53)
#define IDFSC_BIT (6)
#define IDFSC_MAX (1UL << IDFSC_BIT)
#define IDFSC_MASK (IDFSC_MAX - 1)

#define ESR_TO_IDFSC(e) (e & IDFSC_MASK)

#ifndef __ASSEMBLY__
#include <asm/types.h>

static inline bool esr_is_data_abort(u32 esr)
{
	const u32 ec = ESR_ELx_EC(esr);

	return ec == ESR_ELx_EC_DABT_LOW || ec == ESR_ELx_EC_DABT_CUR;
}

#endif /* __ASSEMBLY */

#endif /* __ASM_CPU_ESR_H */